package com.sunda.spmswms.service.impl;

import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.core.conditions.update.UpdateWrapper;
import com.baomidou.mybatisplus.core.toolkit.StringUtils;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.sunda.spmscommon.Constans;
import com.sunda.spmscommon.ResponseResult;
import com.sunda.spmswms.entity.*;
import com.sunda.spmswms.mapper.*;
import com.sunda.spmswms.service.ISapBoxNoteWithdraw;
import com.sunda.spmswms.service.IWhsOperateLogService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.transaction.interceptor.TransactionAspectSupport;

import java.util.ArrayList;
import java.util.List;


@Service
public class SapBoxNoteWithdraw extends ServiceImpl<SapBoxNoteMapper, SapBoxNote> implements ISapBoxNoteWithdraw {

    @Autowired
    SapBoxNoteMapper sapBoxNoteMapper;
    @Autowired
    SapDeliveryNoteDtlMapper sapDeliveryNoteDtlMapper;
    @Autowired
    SapDeliveryNoteMapper sapDeliveryNoteMapper;

    @Autowired
    SapBoxNoteDtlMapper sapBoxNoteDtlMapper;

    @Autowired
    WhsInventoryInfoServiceImpl whsInventoryInfoService;
    @Autowired
    WhsStorageInventoryServiceImpl whsStorageInventoryService;

    @Autowired
    ShelfOnTaskServiceImpl shelfOnTaskService;
    @Autowired
    ShelfOnTaskMapper shelfOnTaskMapper;

    @Autowired
    ShelfOnTaskDtlServiceImpl shelfOnTaskDtlService;
    @Autowired
    ShelfOnTaskDtlMapper shelfOnTaskDtlMapper;

    @Autowired
    WhsStorageServiceImpl whsStorageService;

    @Autowired
    WithdrawTaskServiceImpl withdrawTaskService;

    @Autowired
    IWhsOperateLogService iWhsOperateLogService;

    /*
     * 1. 根据deliveryNoteSap获取入库任务，取得入库任备状态
     * 2. 若有任何未完成的上,下架任务,撤销失败
     *   3. 根据箱码，找到库位对照表
     *   4. 检查储位库存，如果所有箱码都还在原储位，则允许撤销，如果有任何的箱码不能从原上架储位找到，则不允许撤销，返回撤销失败
     *   5. 若已同步到SAP，则调用SAP冲消接口，成功允许继续撤销，失败，返回不允许撤销
     *   6. 扣减储位库存
     * 7. 扣减仓库库存
     * 8. 重置SAP_BOX_NOTE_DTL
     * 9. 重置 SAP_BOX_NOTE
     * */


    /**
     * 检查是否可以冲销
     */
    @Override
    public ResponseResult isWithdrawableX(String deliveryNoteSap, String userId, String createDate) {
        SapDeliveryNote sapDeliveryNote = getSapDeliveryNote(deliveryNoteSap);
        List<SapDeliveryNoteDtl> sapDeliveryNoteDtls = sapDeliveryNoteDtlMapper.selectList(new QueryWrapper<SapDeliveryNoteDtl>().eq("DELIVERY_NOTE_SAP", deliveryNoteSap));
        List<SapBoxNote> sapBoxNotes = sapBoxNoteMapper.selectList(new QueryWrapper<SapBoxNote>().eq("PACKAGE_NOTE", sapDeliveryNote.getPackageNote()));
        if (null == sapDeliveryNote || null == sapDeliveryNoteDtls || sapDeliveryNoteDtls.size() <= 0 || null == sapBoxNotes || sapBoxNotes.size() <= 0) {
            // 无效的 sapDN号
            return ResponseResult.error("deliveryNoteSap: " + deliveryNoteSap + " is not validate, please double check");
        }
        SapDeliveryNoteDtl sapDeliveryNoteDtl = sapDeliveryNoteDtls.get(0);
        String werks = sapDeliveryNoteDtl.getWerks();
        String whsLocationCode = sapDeliveryNoteDtl.getWhsLocationCode();
        String packageNote = sapDeliveryNote.getPackageNote();
        if (StringUtils.isEmpty(packageNote)) {
            // 非备件货
            return ResponseResult.error("packageNote is null");
        }

        String spmsStatus = sapDeliveryNote.getSpmsStatus();
        spmsStatus = StringUtils.isEmpty(spmsStatus) ? "0" : spmsStatus;
        List<ShelfOnTask> shelfOnTasks;
        /*
         * 备件货收货路径
         * null/0(待到货） --> 2 已下发PDA --> 6 待上传SAP --> 7 上传SAP失败 --> 8 收货完成 --> 0 已冲销
         * */
        switch (spmsStatus) {
            case "0":
                //  还没有开始的任务
                return ResponseResult.error("The given deliveryNoteSap:" + deliveryNoteSap + " not start yet");
            case "1":
                // 不适用于备件货，返回错误
                return ResponseResult.error("Spms Staus 1 (已到货) not applicable for the given deliveryNoteSap:" + deliveryNoteSap);
            case "2":
                // 已下发到PDA， 尚未开始收货，可以冲销
                return ResponseResult.success().add("spmsStatus", spmsStatus).add("sapVoucherNumber", sapDeliveryNote.getSapVoucherNumber()).add("sapVoucherYear", sapDeliveryNote.getSapVoucherYear());
            case "3":
                // 不适用于备件货，返回错误
                return ResponseResult.error("Spms Staus 3 (收货中) not applicable for the given deliveryNoteSap:" + deliveryNoteSap);
            case "4":
                // 不适用于备件货，返回错误
                // 备件货收货状态为 0/null 侍到货 -- > 2 下发到PDA --> 6 侍上传SAP,  上架任务的状态由上下架任务控制
                return ResponseResult.error("Spms Staus 4 (待上架) not applicable for the given deliveryNoteSap:" + deliveryNoteSap);
            case "5":
                // 不适用于备件货，返回错误
                // 备件货收货状态为 0/null 侍到货 -- > 2 下发到PDA --> 6 侍上传SAP,  上架任务的状态由上下架任务控制
                return ResponseResult.error("Spms Staus 5 (上架中) not applicable for the given deliveryNoteSap:" + deliveryNoteSap);
            case "6":
            case "7":
            case "8":
            case "11":
                shelfOnTasks = getShelfOnTask(deliveryNoteSap);
                if (checkIsAnyIncompletedTask(shelfOnTasks)) {
                    return ResponseResult.error("请先完成所有的关联上,下架任务");
                }

                ResponseResult checkResult = checkWithDrawableX(werks, whsLocationCode, sapBoxNotes);
                if (checkResult.getCode() != 200) {
                    // 检查库存失败
                    return checkResult;
                }
                return ResponseResult.success().add("spmsStatus", spmsStatus).add("sapVoucherNumber", sapDeliveryNote.getSapVoucherNumber()).add("sapVoucherYear", sapDeliveryNote.getSapVoucherYear());
            default:
                return ResponseResult.error("SpmsStatus incorrect for sapDeliveryNote: " + deliveryNoteSap);

        }
    }

    /*
     * 执行库内数据冲销
     * */
    @Override
    public ResponseResult withdrawSapBoxNote(String deliveryNoteSap, String userId, String createDate, String newSapVoucherNumber, String mobileType) {
        SapDeliveryNote sapDeliveryNote = getSapDeliveryNote(deliveryNoteSap);
        List<SapDeliveryNoteDtl> sapDeliveryNoteDtls = sapDeliveryNoteDtlMapper.selectList(new QueryWrapper<SapDeliveryNoteDtl>().eq("DELIVERY_NOTE_SAP", deliveryNoteSap));
        List<SapBoxNote> sapBoxNotes = sapBoxNoteMapper.selectList(new QueryWrapper<SapBoxNote>().eq("PACKAGE_NOTE", sapDeliveryNote.getPackageNote()));
        if (null == sapDeliveryNote || null == sapDeliveryNoteDtls || sapDeliveryNoteDtls.size() <= 0 || null == sapBoxNotes || sapBoxNotes.size() <= 0) {
            // 无效的 sapDN号
            return ResponseResult.error("deliveryNoteSap: " + deliveryNoteSap + " is not validate, please double check");
        }
        SapDeliveryNoteDtl sapDeliveryNoteDtl = sapDeliveryNoteDtls.get(0);
        String werks = sapDeliveryNoteDtl.getWerks();
        String whsLocationCode = sapDeliveryNoteDtl.getWhsLocationCode();
        String packageNote = sapDeliveryNote.getPackageNote();
        if (StringUtils.isEmpty(packageNote)) {
            // 非备件货
            return ResponseResult.error("packageNote is null");
        }
        String spmsStatus = sapDeliveryNote.getSpmsStatus();
        spmsStatus = StringUtils.isEmpty(spmsStatus) ? "0" : spmsStatus;
        List<ShelfOnTask> shelfOnTasks;
        /*
         * 备件货收货路径
         * null/0(待到货） --> 2 已下发PDA --> 6 待上传SAP --> 7 上传SAP失败 --> 8 收货完成 --> 0 已冲销
         * */
        switch (spmsStatus) {
            case "2":
                // 已下发到PDA， 尚未开始收货，重置SAP_DELIVERY_NOTE Table
                return updateSapDeliveryNote(deliveryNoteSap);
            case "6":
            case "7":
            case "8":
            case "11":
                shelfOnTasks = getShelfOnTask(deliveryNoteSap);
                if (checkIsAnyIncompletedTask(shelfOnTasks)) {
                    return ResponseResult.error("请完成所有关联的上,下架任务");
                }
                // 执行冲销
                return withDrawX(werks, whsLocationCode, deliveryNoteSap, sapBoxNotes, userId);
            default:
                return ResponseResult.error("SpmsStatus incorrect for sapDeliveryNote: " + deliveryNoteSap);
        }

    }


    /**
     * 检查是否有未完成的ShelfOnTask
     */
    boolean checkIsAnyIncompletedTask(List<ShelfOnTask> shelfOnTasks) {
        if (null != shelfOnTasks && shelfOnTasks.size() > 0) {
            for (int i = 0; i < shelfOnTasks.size(); i++) {
                String taskStatus = shelfOnTasks.get(i).getTaskStatus();
                if (taskStatus.equals("1") || taskStatus.equals("2")) {
                    return true;
                }
            }
        }
        return false;
    }

    /**
     * 检查仓库库存，储位库存，是否满足回撤条件
     */
    private ResponseResult checkWithDrawableX(String werks, String whsLocationCode, List<SapBoxNote> sapBoxNotes) {

        // 检查是否所有的箱码都在WHS_INVENTORY_INFO中
        for (int i = 0; i < sapBoxNotes.size(); i++) {
            SapBoxNote sapBoxNote = sapBoxNotes.get(i);
            if (null!=sapBoxNote.getBoxQtyReceived() && sapBoxNote.getBoxQtyReceived() > 0) {
                WhsInventoryInfo whs = whsInventoryInfoService.getWhsInventoryInfoByBoxNote(sapBoxNotes.get(i).getBoxNote(), werks, whsLocationCode);
                if (null == whs || !whs.getWerks().equals(werks) || !whs.getWhsLocationCode().equals(whsLocationCode)) {
                    return ResponseResult.error("Error when checking WhsInventoryInfo, boxNote: " + sapBoxNotes.get(i).getBoxNote() + " not exist in WhsInventoryInfo");
                }
            }
        }
        // 检查是否所有的箱码都在WHS_STORAGE_INVENTORY中
        ResponseResult responseResult = checkStorageInventory(werks, whsLocationCode, sapBoxNotes);
        if (responseResult.getCode() != 200) {
            // 检查库存失败，有箱码在储位库存未找到，此时因为有没有未完成的储位库存，所以箱码应该在储位不存在，因此返回错误
            return responseResult;
        }
        return ResponseResult.success();
    }

    @Transactional(rollbackFor = Exception.class)
    public ResponseResult withDrawX(String werks, String whsLocationCode, String deliveryNoteSap, List<SapBoxNote> sapBoxNotes, String userId) {

        try {
            // 2021 July 1, 为了简化备件入库撤销的过程，不再生成下架任务，直接扣减储位库存，记录日志
            for (int i = 0; i < sapBoxNotes.size(); i++) {
                SapBoxNote sapBoxNote = sapBoxNotes.get(i);
                if (null!=sapBoxNote.getBoxQtyReceived() && sapBoxNote.getBoxQtyReceived() > 0) {
                    //获取当前box所在的储位
                    WhsStorageInventory currentBoxStorage = whsStorageInventoryService.getBoxNoteStorage(sapBoxNote.getBoxNote());
                    if (null == currentBoxStorage) {
                        throw new Exception("箱码无储位库存");
                    }
                    //获取储位所属的werks,whsLocationCode
                    WhsStorage currentStorage = whsStorageService.getWhsStorageByUuid(currentBoxStorage.getUuid());
                    if (null == currentStorage || !currentStorage.getWerks().equals(werks) || !currentStorage.getWhsLocationCode().equals(whsLocationCode)) {
                        throw new Exception("当前箱码所在的储位与入库储位不属于同一仓库 boxNote:" + sapBoxNote.getBoxNote() + ",入库工厂:" + werks +
                                ",入库仓库:" + whsLocationCode + ",当前工厂:" + currentStorage.getWerks() +
                                ",当前仓库:" + currentStorage.getWhsLocationCode());
                    }
                    //删除储位库存
                    if (whsStorageInventoryService.deleteStorageByBoxNoteStorageId(currentBoxStorage.getUuid(), sapBoxNote.getBoxNote()) < 0) {
                        throw new Exception("删除箱码储位库存失败");
                    }
                    ;
                    // 插入日志
                    iWhsOperateLogService.insertWhsOperateLog(
                            Constans.WhsOperateLog_DocumentType_NanShaStorageLog,
                            currentBoxStorage.getUuid(),
                            "",
                            sapBoxNote.getBoxNote(),
                            1,
                            Constans.WhsOperateLog_OperationType_ShelfOff,
                            deliveryNoteSap,
                            Constans.WHS_WhsIn_Withdraw_ShelfOffX,
                            userId,
                            Constans.WHS_WhsIn_WithdrawX,
                            werks,
                            whsLocationCode);
                }
            }

            // 扣减仓库存
            for (int i = 0; i < sapBoxNotes.size(); i++) {
                // 扣减仓库库存
                ResponseResult whsInfoRes = deductWhsInventoryInfo(werks, whsLocationCode, sapBoxNotes.get(i).getBoxNote(), userId);
                if (whsInfoRes.getCode() != 200) {
                    throw new Exception(whsInfoRes.getMsg());
                }
                // 重置SAP_BOX_NOTE_DTL
                ResponseResult sapBoxDtlRes = updateSapBoxNoteDtl(sapBoxNotes.get(i).getBoxNote());
                if (sapBoxDtlRes.getCode() != 200) {
                    throw new Exception(sapBoxDtlRes.getMsg());
                }
                // 重置 SAP_BOX_NOTE
                ResponseResult sapBoxNoteRes = updateSapBoxNote(sapBoxNotes.get(i).getBoxNote());
                if (sapBoxNoteRes.getCode() != 200) {
                    throw new Exception(sapBoxNoteRes.getMsg());
                }
            }
            // 重置 SAP_DELIVERY_NOTE
            ResponseResult uRes = updateSapDeliveryNote(deliveryNoteSap);
            if (uRes.getCode() != 200) {
                throw new Exception(uRes.getMsg());
            }
            return uRes;
        } catch (Exception e) {
            e.printStackTrace();
            TransactionAspectSupport.currentTransactionStatus().setRollbackOnly();
            return ResponseResult.error(e.getMessage());
        }

    }

    /* 1. 根据deliveryNoteSap获取入库任务，取得入库任务状态 */
    @Override
    public SapDeliveryNote getSapDeliveryNote(String deliveryNoteSap) {
        return sapDeliveryNoteMapper.selectOne(new QueryWrapper<SapDeliveryNote>().eq("DELIVERY_NOTE_SAP", deliveryNoteSap));
    }

    /* 2. 根据deliveryNoteSap找到所有上架任务 */
    @Override
    public List<ShelfOnTask> getShelfOnTask(String deliveryNoteSap) {
        return shelfOnTaskMapper.selectList(new QueryWrapper<ShelfOnTask>().eq("DELIVERY_NOTE_SAP", deliveryNoteSap).eq("TASK_TYPE", "1"));
    }

    /* 3. 根据uuid找到上架任务明细，返回箱码，库位对照表*/
    @Override
    public List<ShelfOnTaskDtl> getShelfOnTaskDtl(String uuid) {
        return shelfOnTaskDtlMapper.selectList(new QueryWrapper<ShelfOnTaskDtl>().eq("UUID", uuid));
    }

    /* 4. 检查储位库存，如果所有箱码都在储位能找到，则允许撤销，如果有任何的箱码不能从储位找到，则不允许撤销，返回撤销失败*/
    @Override
    public ResponseResult checkStorageInventory(String werks, String whsLocationCode, List<SapBoxNote> sapBoxNotes) {
        for (int i = 0; i < sapBoxNotes.size(); i++) {
            SapBoxNote sapBoxNote = sapBoxNotes.get(i);
            if (null!=sapBoxNote.getBoxQtyReceived() && sapBoxNote.getBoxQtyReceived() > 0) {
                WhsStorageInventory whsStorageInventory = whsStorageInventoryService.getBoxNoteStorage(sapBoxNote.getBoxNote());
                if (null == whsStorageInventory) {
                    return ResponseResult.error("储位库存检查失败,箱码:" + sapBoxNote.getBoxNote() + " 未找到");
                }

                WhsStorage whsStorage = whsStorageService.getWhsStorageByUuid(whsStorageInventory.getUuid());

                if ((!whsStorage.getWerks().equals(werks)) || (!whsStorage.getWhsLocationCode().equals(whsLocationCode))) {
                    return ResponseResult.error("储位库存检查失败,箱码:" + sapBoxNote.getBoxNote() + " 未找到");
                }
            }
        }
        return ResponseResult.success();
    }

    /*检查储位库存，确保所有的箱码在储位库存中不存在，则允许撤销，如果有任何的箱码在储位存在，则不应该再撤销*/
    @Override
    public ResponseResult ensureBoxNoteNotExit(String werks, String
            whsLocationCode, List<SapBoxNote> sapBoxNotes) {
        for (int i = 0; i < sapBoxNotes.size(); i++) {
            SapBoxNote sapBoxNote = sapBoxNotes.get(i);
            WhsStorageInventory whsStorageInventory = whsStorageInventoryService.getBoxNoteStorage(sapBoxNote.getBoxNote());
            if (null != whsStorageInventory) {
                return ResponseResult.error("储位库存检查失败,箱码:" + sapBoxNote.getBoxNote() + " 已存在");
            }
        }
        return ResponseResult.success();
    }

    /* 6. 对于已上架的入库任务， 生成下架任务单，完成下架任务，扣减储位库存*/
    @Override
    public ResponseResult createShelfOnTaskDeduct(ShelfOnTask
                                                          shelfOnTask, List<ShelfOnTaskDtl> shelfOnTaskDtls, String userId, String createDate) {

        // 新建下架任务和明细行项
        ShelfOnTask deductTask = shelfOnTaskService.generateShelfOnTaskV1(userId, createDate.replaceAll("-", ""), shelfOnTask.getDeliveryNoteSap(), "2", "webClient");
        if (null == deductTask) {
            return ResponseResult.error("Error when create Deduct Task");
        }

        //完成下架任务
        ShelfOnTask completeDeductTaskRes = shelfOnTaskService.completeShelfOnTaskByUuid(userId, deductTask.getUuid(), "WebClient", "1", "3");
        if (null == completeDeductTaskRes) {
            // 失败，返回
            return ResponseResult.error("Error when complete Deduct Task");
        }

        // 完成下架任务明细行项更新，更新储位库存
        return shelfOnTaskDtlService.completeDeductTaskDtlByBoxNote(deductTask.getUuid(), shelfOnTaskDtls, userId);

    }


    /* 7. 扣减仓库库存*/
    @Override
    public ResponseResult deductWhsInventoryInfo(String werks, String whsLocationCode, String boxNote, String userId) {
        return whsInventoryInfoService.deductWhsInventoryInfoX(werks, whsLocationCode, boxNote, userId);
    }


    /* 8. 重置SAP_BOX_NOTE_DTL DOMESTIC_QTY_RECEIVED 为0，DOMESTIC_QTY_RECEIVABLE 为0*/
    @Override
    public ResponseResult updateSapBoxNoteDtl(String boxNote) {
        try {
            UpdateWrapper updateWrapper = new UpdateWrapper<SapBoxNoteDtl>().eq("BOX_NOTE", boxNote);
            SapBoxNoteDtl sapBoxNoteDtl = new SapBoxNoteDtl();
            sapBoxNoteDtl.setDomesticQtyReceivable(0.0);
            sapBoxNoteDtl.setDomesticQtyReceived(0.0);
            sapBoxNoteDtlMapper.update(sapBoxNoteDtl, updateWrapper);
            return ResponseResult.success();
        } catch (Exception e) {
            e.printStackTrace();
            return ResponseResult.error("重置SAP_BOX_NOTE_DTL DOMESTIC_QTY_RECEIVED 为0，DOMESTIC_QTY_RECEIVABLE 为0,失败");
        }

    }

    /* 9. 重置 SAP_BOX_NOTE, BOX_QTY_RECEIVED为0，ITDM_STATUS重置为0*/
    @Override
    public ResponseResult updateSapBoxNote(String boxNote) {
        try {
            UpdateWrapper updateWrapper = new UpdateWrapper<SapBoxNote>().eq("BOX_NOTE", boxNote);
            SapBoxNote sapBoxNote = new SapBoxNote();
            sapBoxNote.setBoxQtyReceived(0);
            sapBoxNote.setItemStatus("0");
            sapBoxNoteMapper.update(sapBoxNote, updateWrapper);
            return ResponseResult.success();
        } catch (Exception e) {
            e.printStackTrace();
            return ResponseResult.error("重置 SAP_BOX_NOTE, BOX_QTY_RECEIVED为0，ITDM_STATUS重置为0,失败");
        }

    }

    /* 10. 重置 SAP_DELIVERY_NOTE

     *  */
    @Override
    public ResponseResult updateSapDeliveryNote(String deliveryNoteSap) {
        try {
            UpdateWrapper updateWrapper = new UpdateWrapper<SapDeliveryNote>().eq("DELIVERY_NOTE_SAP", deliveryNoteSap);
            SapDeliveryNote sapDeliveryNote = new SapDeliveryNote();
            sapDeliveryNote.setSpmsStatus("0");
            // Aug 3, kpzhang@cn.ibm.com,  按客户要求,采购入库撤销,只改状态
//            sapDeliveryNote.setDocumentDate(null);
//            sapDeliveryNote.setPostingDate(null);
//            sapDeliveryNote.setMobileType(null);
//            sapDeliveryNote.setUserId(null);
//            sapDeliveryNote.setSapVoucherNumber(null);
//            sapDeliveryNote.setSapVoucherYear(null);
            sapDeliveryNoteMapper.update(sapDeliveryNote, updateWrapper);
            return ResponseResult.success();
        } catch (Exception e) {
            e.printStackTrace();
            return ResponseResult.error("重置SAP_DELIVERY_NOTE DOCUMENT_DATE,POSTING_DATE,MOBILE_TYPE,USER_ID, PDA_SN,SAP_VOUCHER_NUMBER,SAP_VOUCHER_YEAR设为空存,失败");
        }

    }
}



